package me.zhengjie.modules.quartz.utils

import cn.hutool.extra.template.TemplateConfig
import cn.hutool.extra.template.TemplateUtil
import me.zhengjie.common.utils.*
import me.zhengjie.modules.quartz.domain.QuartzJob
import me.zhengjie.modules.quartz.domain.QuartzLog
import me.zhengjie.modules.quartz.repository.QuartzLogRepository
import me.zhengjie.modules.quartz.service.QuartzJobService
import me.zhengjie.tools.domain.vo.EmailVo
import me.zhengjie.tools.service.EmailService
import org.quartz.JobExecutionContext
import org.slf4j.LoggerFactory
import org.springframework.scheduling.annotation.Async
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor
import org.springframework.scheduling.quartz.QuartzJobBean
import java.util.*
import java.util.concurrent.Future

/**
 * 参考人人开源，https://gitee.com/renrenio/renren-security
 * @author /
 * @date 2019-01-07
 */
@Async
class ExecutionJob : QuartzJobBean() {
    private val logger = LoggerFactory.getLogger(this.javaClass)
    private val executor: ThreadPoolTaskExecutor = SpringContextHolder.getBean("elAsync")

    override fun executeInternal(context: JobExecutionContext) {
        val quartzJob = context.mergedJobDataMap[QuartzJob.Companion.JOB_KEY] as QuartzJob?
        // 获取spring bean
        val quartzLogRepository: QuartzLogRepository = SpringContextHolder.Companion.getBean<QuartzLogRepository>(
            QuartzLogRepository::class.java
        )
        val quartzJobService: QuartzJobService = SpringContextHolder.Companion.getBean<QuartzJobService>(
            QuartzJobService::class.java
        )

        val redisUtils: RedisUtil = SpringContextHolder.getBean(RedisUtil::class.java)

        var uuid: String = quartzJob!!.uuid!!

        val log = QuartzLog()
        log.jobName = quartzJob.jobName
        log.beanName = quartzJob.beanName
        log.methodName = quartzJob.methodName
        log.params = quartzJob.params
        val startTime = System.currentTimeMillis()
        log.cronExpression = quartzJob.cronExpression
        try {
            // 执行任务
            logger.info("任务准备执行，任务名称：{}", quartzJob.jobName)
            val task = QuartzRunnable(
                quartzJob.beanName, quartzJob.methodName,
                quartzJob.params!!
            )
            val future: Future<*> = executor!!.submit(task)
            future.get()
            val times = System.currentTimeMillis() - startTime
            log.time = times
            // 任务状态
            log.isSuccess = true
            logger.info("任务执行完毕，任务名称：{} 总共耗时：{} 毫秒", quartzJob.jobName, times)

            // 判断是否存在子任务
            if (org.apache.commons.lang3.StringUtils.isNotBlank(quartzJob.subTask)) {
                val tasks: Array<String?> = quartzJob.subTask!!.split("[,，]".toRegex()).dropLastWhile { it.isEmpty() }
                    .toTypedArray()
                // 执行子任务
                quartzJobService.executionSubJob(tasks)
            }

        } catch (e: Exception) {
            if (org.apache.commons.lang3.StringUtils.isNotBlank(uuid)) {
                redisUtils.set(uuid, false)
            }
            logger.error("任务执行失败，任务名称：{}" + quartzJob.jobName, e)
            val times = System.currentTimeMillis() - startTime
            log.time = times
            // 任务状态 0：成功 1：失败
            log.isSuccess = false
            log.exceptionDetail = ThrowableUtil.getStackTrace(e)
            // 任务如果失败了则暂停
            // 任务如果失败了则暂停
            if (quartzJob.pauseAfterFailure != null && quartzJob.pauseAfterFailure!!) {
                quartzJob.isPause= false
                //更新状态
                quartzJobService.updateIsPause(quartzJob)
            }
            if (quartzJob.email != null) {
                val emailService: EmailService = SpringContextHolder.getBean(EmailService::class.java)
                // 邮箱报警
                if (org.apache.commons.lang3.StringUtils.isNoneBlank(quartzJob.email)) {
                    val emailVo: EmailVo = taskAlarm(quartzJob, ThrowableUtil.getStackTrace(e))!!
                    emailService.send(emailVo, emailService.find())
                }
            }
        } finally {
            quartzLogRepository.save(log)
        }
    }

    fun taskAlarm(quartzJob: QuartzJob, msg: String): EmailVo? {
        val emailVo = EmailVo()
        emailVo.subject = "定时任务【" + quartzJob.jobName + "】执行失败，请尽快处理！"
        val data: MutableMap<String?, Any?> = HashMap(16)
        data["task"] = quartzJob
        data["msg"] = msg
        val engine = TemplateUtil.createEngine(TemplateConfig("template", TemplateConfig.ResourceMode.CLASSPATH))
        val template = engine.getTemplate("taskAlarm.ftl")
        emailVo.content =template.render(data)
        val emails = Arrays.asList(*quartzJob.email!!.split("[,，]".toRegex()).dropLastWhile { it.isEmpty() }
            .toTypedArray())
        emailVo.tos = emails
        return emailVo
    }
    companion object {
        // 该处仅供参考
        //private val executor = ThreadPoolExecutorUtil.poll
    }
}